import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Scanner;

public class RemoteControlMain {

    private static final String IP_V4_ADDRESS_REGEX = "^(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])$";

    private static final String ADB_PATH = ".\\platform-tools\\adb.exe";
    private static final String SCRCPY_PATH = ".\\scrcpy-win64-v1.23\\scrcpy.exe";

    private static final ArrayList<Process> processes = new ArrayList<>();

//    private static final String ADB_PATH = "F:\\sdkNew\\platform-tools\\adb.exe";
//    private static final String SCRCPY_PATH = "D:\\scrcpy-win64-v1.23\\scrcpy.exe";

    public static void main(String[] args) {

        String os = System.getenv("OS");
        printMsg("当前操作系统：" + os);

        if (!os.toLowerCase().startsWith("windows")) {
            printMsg("请使用Windows系统运行本程序！");
            return;
        }
        Scanner scanner = new Scanner(System.in);
        Runtime runtime = Runtime.getRuntime();
        int result = listDevices(runtime);
        switch (result) {
            case ConstantsCode.SUCCESS:
                break;
            case ConstantsCode.ERROR:
                exit();
                return;
            case ConstantsCode.EXIT:
                return;
            case ConstantsCode.FAIL:
            default:
                int connectDeviceByNetwork = connectDeviceByNetwork(runtime, scanner);
                if (connectDeviceByNetwork != ConstantsCode.SUCCESS) {
                    exit();
                    return;
                }
                break;
        }
        result = doRemoteControl(runtime, scanner);
        switch (result) {
            case ConstantsCode.SUCCESS:
            case ConstantsCode.ERROR:
            case ConstantsCode.EXIT:
            case ConstantsCode.FAIL:
            default:
                break;
        }
        exit();
    }

    /**
     * 开始执行远程控制
     *
     * @param runtime 程序运行环境
     * @param scanner 控制台输入
     */
    private static int doRemoteControl(Runtime runtime, Scanner scanner) {
        printMsg("请输入设备类型（1 福袋机，2 通用设备，3 自定义控制参数）(输入exit或quit退出程序)：");
        String deviceType;
        while (true) {
            boolean nextLine = scanner.hasNextLine();
            if (!nextLine) {
                continue;
            }
            String s = scanner.nextLine().trim();
            if (s.isEmpty()) {
                printMsg("请输入设备类型（1 福袋机，2 通用设备，3 自定义控制参数）(输入exit或quit退出程序)：");
                continue;
            }
            if (!s.equals("1") && !s.equals("2") && !s.equals("3")) {
                if (s.equalsIgnoreCase("exit") || s.equalsIgnoreCase("quit")) {
                    return ConstantsCode.EXIT;
                }
                printMsg("请输入正确的设备类型（1 福袋机，2 通用设备，3 自定义控制参数）(输入exit或quit退出程序)：");
                continue;
            }
            deviceType = s;
            break;
        }
        printMsg("正在发送远程控制命令，请耐心等待...");
        String lockVideoOrientation;
        String rotation;
        switch (deviceType) {
            case "1":
                lockVideoOrientation = "1";
                rotation = "3";
                break;
            case "3":
                lockVideoOrientation = getLockVideoOrientation(scanner);
                if (lockVideoOrientation == null) {
                    return ConstantsCode.ERROR;
                }
                rotation = getRotation(scanner);
                if (rotation == null) {
                    return ConstantsCode.ERROR;
                }
                break;
            case "2":
            default:
                lockVideoOrientation = "0";
                rotation = "0";
                break;
        }
        try {
            Process process = runtime.exec(SCRCPY_PATH + " --lock-video-orientation=" + lockVideoOrientation + " --rotation " + rotation);
            processes.add(process);
            InputStream inputStream = process.getInputStream();
            startPrintThread(process, inputStream);
            process.waitFor();
            return ConstantsCode.SUCCESS;
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
            return ConstantsCode.ERROR;
        }
    }

    /**
     * 获取窗口旋转角度
     * @param scanner 控制台输入
     * @return 旋转角度
     */
    private static String getRotation(Scanner scanner) {
        //0: 无旋转
        //1: 逆时针旋转 90°
        //2: 旋转 180°
        //3: 顺时针旋转 90°
        printMsg("请输入窗口旋转角度（0 无旋转，1 逆时针旋转 90°，2 旋转 180°，3 顺时针旋转 90°）(输入exit或quit退出程序)：");
        String result;
        while (true) {
            boolean nextLine = scanner.hasNextLine();
            if (!nextLine) {
                continue;
            }
            String s = scanner.nextLine().trim();
            if (s.isEmpty()) {
                printMsg("请输入窗口旋转角度（0 无旋转，1 逆时针旋转 90°，2 旋转 180°，3 顺时针旋转 90°）(输入exit或quit退出程序)：");
                continue;
            }
            if (!s.equals("0") && !s.equals("1") && !s.equals("2") && !s.equals("3")) {
                if (s.equalsIgnoreCase("exit") || s.equalsIgnoreCase("quit")) {
                    result = null;
                    break;
                }
                printMsg("请输入正确的窗口旋转角度（0 无旋转，1 逆时针旋转 90°，2 旋转 180°，3 顺时针旋转 90°）(输入exit或quit退出程序)：");
                continue;
            }
            result =  s;
            break;
        }
        return result;
    }

    /**
     * 获取屏幕锁定方向
     *
     * @param scanner 控制台输入
     * @return 屏幕锁定方向
     */
    private static String getLockVideoOrientation(Scanner scanner) {
        //0 自然方向
        //1 逆时针旋转 90
        //2 180°
        //3 顺时针旋转 90
        printMsg("请输入屏幕锁定方向（0 自然方向，1 逆时针旋转 90，2 180°，3 顺时针旋转 90）(输入exit或quit退出程序)：");
        String result;
        while (true) {
            boolean nextLine = scanner.hasNextLine();
            if (!nextLine) {
                continue;
            }
            String s = scanner.nextLine().trim();
            if (s.isEmpty()) {
                printMsg("请输入屏幕锁定方向（0 自然方向，1 逆时针旋转 90，2 180°，3 顺时针旋转 90）(输入exit或quit退出程序)：");
                continue;
            }
            if (!s.equals("0") && !s.equals("1") && !s.equals("2") && !s.equals("3")) {
                if (s.equalsIgnoreCase("exit") || s.equalsIgnoreCase("quit")) {
                    result = null;
                    break;
                }
                printMsg("请输入正确的屏幕锁定方向（0 自然方向，1 逆时针旋转 90，2 180°，3 顺时针旋转 90）(输入exit或quit退出程序)：");
                continue;
            }
            result = s;
            break;
        }
        return result;
    }

    private static void startPrintThread(Process process, InputStream inputStream) {
        new Thread(() -> {
            while (true) {
                if (!process.isAlive()) {
                    break;
                }
                try {
                    int available = inputStream.available();
                    if (available > 0) {
                        byte[] bytes = new byte[available];
                        int read = inputStream.read(bytes);
                        if (read < 0) {
                            break;
                        }
                        String s = new String(bytes, StandardCharsets.UTF_8);
                        printMsg(s);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    break;
                }
            }
        }).start();
    }

    private static void printMsg(String x) {
        System.out.println(x);
    }

    /**
     * 退出程序
     */
    private static void exit() {
        for (Process process : processes) {
            if (process.isAlive()) {
                process.destroy();
            }
        }
        printMsg("程序已退出");
        System.exit(0);
    }

    private static int connectDeviceByNetwork(Runtime runtime, Scanner scanner) {
        printMsg("如果您的设备可用网络进行连接，请输入目标设备IP地址(输入exit或quit退出程序)：");
        String ip;
        while (true) {
            boolean nextLine = scanner.hasNextLine();
            if (!nextLine) {
                continue;
            }
            String s = scanner.nextLine().trim();
            if (s.isEmpty()) {
                printMsg("请输入目标设备IP地址(输入exit或quit退出程序)：");
                continue;
            }
            boolean valid = isIp4Valid(s);
            if (!valid) {
                if (s.equalsIgnoreCase("exit") || s.equalsIgnoreCase("quit")) {
                    return ConstantsCode.EXIT;
                }
                printMsg("请输入正确的IP地址(输入exit或quit退出程序)：");
                continue;
            }
            ip = s;
            break;
        }
        printMsg("正在连接目标设备，请耐心等待...");
        try {
            Process process = runtime.exec(ADB_PATH + " connect " + ip);
            processes.add(process);
            process.waitFor();
            InputStream inputStream = process.getInputStream();
            byte[] bytes = new byte[inputStream.available()];
            int read = inputStream.read(bytes);
            if (read < 0) {
                printMsg("命令执行结果获取失败！");
                return ConstantsCode.ERROR;
            }
            String s = new String(bytes, StandardCharsets.UTF_8);
            printMsg(s);
            PrintWriter writer = new PrintWriter(new StringWriter());
            writer.println();
            if (!s.toLowerCase().startsWith("connected to") && !s.toLowerCase().startsWith("already connected to")) {
                printMsg("与目标设备连接失败！");
                return ConstantsCode.FAIL;
            }
            return ConstantsCode.SUCCESS;
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
            printMsg("命令执行失败，请检查运行环境是否正常");
            return ConstantsCode.ERROR;
        }
    }

    /**
     * 列出全部已经连接的设备
     *
     * @param runtime 当前运行环境
     */
    private static int listDevices(Runtime runtime) {
        try {
            Process process = runtime.exec(ADB_PATH + " devices");
            processes.add(process);
            int waitFor = process.waitFor();
            if (waitFor != 0) {
                printMsg("命令运行失败！");
                return ConstantsCode.ERROR;
            }
            InputStream inputStream = process.getInputStream();
            byte[] bytes = new byte[inputStream.available()];
            inputStream.read(bytes);
            String result = new String(bytes, StandardCharsets.UTF_8);
            printMsg(result);
            String[] split = result.split("\n");
            if (split.length <= 2) {
                printMsg("没有已经连接的设备,请使用USB连接！\n\n");
                return ConstantsCode.FAIL;
            }
            if (split.length > 3) {
                printMsg("连接的设备,不只一个，请断开多余的设备！\n\n");
                return ConstantsCode.ERROR;
            }
            return ConstantsCode.SUCCESS;
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
            printMsg("找不到adb.exe，请确认adb已经安装到系统环境变量中！");
            return ConstantsCode.ERROR;
        }
    }

    /**
     * 判断IPV4地址是否合法
     *
     * @param ip IPV4地址
     * @return true：合法；false：不合法
     */
    private static boolean isIp4Valid(String ip) {
        return ip.matches(IP_V4_ADDRESS_REGEX);
    }
}
